/** 
 * @(#)RIPRoutingTable.java
 */

/**
 * @author Didier Gutacker
 * @version 1.0
 * @see Table
 * @see RoutingTableRIP 
 *
 */

import java.util.Vector;
import java.awt.Frame;

public class RIPRoutingTable extends RoutingTableRIP {

  public RIPRoutingTable( int nodeID ) {
    super();
  } // RIPRoutingTable.RIPRoutingTable

  public final boolean update( LinkRIP incomingLink, int destinationID, int metric, LinkRIP l, int infinity ) {

    boolean updated;

    int newMetric = metric + incomingLink.getWeight();
    RIPRoutingEntry entry = (RIPRoutingEntry) lookUp( destinationID );
    
    if ( entry == null && metric < infinity ) {
      entry = new RIPRoutingEntry( this, destinationID, newMetric, incomingLink, infinity );
      entryChangeGuard.acquire();
      entries.addElement( entry );
      entryChangeGuard.release();
      updateTableWindow();
      return true;
    } else if ( entry != null ) {
      if ( metric < infinity ) {
	if ( newMetric > entry.metric ) {
	  if ( entry.l.equals( incomingLink ) ) {
	    entryChangeGuard.acquire();
	    entry.metric = newMetric;
	    if ( entry.metric > entry.infinity ) {
	      entry.infinity = entry.metric + 1;
	    } // if
	    entryChangeGuard.release();
	  } else {
	    entryChangeGuard.acquire();
	    entry.removeChild( incomingLink );
	    entryChangeGuard.release();
	  } // if
	} else if ( newMetric < entry.metric ) {
	  entryChangeGuard.acquire();
	  entry.children = null;
	  updated = entry.update( destinationID, newMetric, incomingLink, entry.infinity );
	  entryChangeGuard.release();
	  updateTableWindow();
	  return updated;
	} else {
	  if ( !entry.l.equals( incomingLink ) ) {
	    if ( getNextHopRouter( incomingLink ) < getNextHopRouter( (LinkRIP) entry.l ) ) {
	      entryChangeGuard.acquire();
	      entry.children = null;
	      entry.l = incomingLink;
	      entryChangeGuard.release();
	      updateTableWindow();
	      return true;
	    } else {
	      entryChangeGuard.acquire();
	      entry.removeChild( incomingLink );
	      entryChangeGuard.release();
	      updateTableWindow();
	    } // if
	  } // if
	} // if
      } else if ( metric == infinity ) {
	if ( getNextHopRouter( incomingLink ) == getNextHopRouter( (LinkRIP) entry.l ) ) {
	  entryChangeGuard.acquire();
	  updated = entry.update( destinationID, infinity, incomingLink, infinity );
	  entryChangeGuard.release();
	  updateTableWindow();
	  return updated;
	} // if
      } else if ( infinity < metric && metric < 2 * infinity ) {
	if ( ! incomingLink.equals( entry.l ) ) {
	  entryChangeGuard.acquire();
	  entry.addChild( incomingLink );
	  entryChangeGuard.release();
	  updateTableWindow();
	} // if
      } // if
    } // if
    return false;
  } // RIPRoutingTable.update

  public final void registerLink( LinkRIP l ) {
    entryChangeGuard.acquire();
    for ( int i = 0; i < entries.size(); i += 1 ) {
      ( (RIPRoutingEntry) entries.elementAt( i ) ).addChild( l );
    } // for
    entryChangeGuard.release();
  } // RIPRoutingTable.registerLink

  public final void deregisterLink( LinkRIP l, int infinity ) {
    entryChangeGuard.acquire();
    for ( int i = 0; i < entries.size(); i += 1 ) {
      RIPRoutingEntry entry = (RIPRoutingEntry) entries.elementAt( i );
      if ( entry.l.equals( l ) ) {
	entry.metric = infinity;
      } // if
      entry.removeChild( l );
    } // for
    entryChangeGuard.release();
  } // RIPRoutingTable.deregisterLink

  public final int getNextHopRouter( LinkRIP l ) {
    int routerID = -1;
    int distance = -1;
    
    entryChangeGuard.acquire();
    for ( int i = 0; i < entries.size(); i += 1 ) {
	if ( ( (RIPRoutingEntry) entries.elementAt( i ) ).l.equals( l ) ) {
	  if ( ( routerID == -1 ) || ( distance >= ( (RIPRoutingEntry) entries.elementAt( i ) ).metric ) ) {
	    routerID = ( (RIPRoutingEntry) entries.elementAt( i ) ).destinationID;
	    distance = ( (RIPRoutingEntry) entries.elementAt( i ) ).metric;
	  } // if
	} // if
    } // for
    entryChangeGuard.release();
    return routerID;
  } // RIPRoutingTable.getNextHopRouter

  public final Vector getForwardInterfaces( int destinationID ) {
    Vector interfaces = new Vector();
    entryChangeGuard.acquire();
    RIPRoutingEntry entry = (RIPRoutingEntry) lookUp( destinationID );
    if ( entry == null ) {
      entryChangeGuard.release();
      return null;
    } // if
    interfaces.addElement( (LinkRIP) entry.l );
    entryChangeGuard.release();
    updateTableWindow();
    return interfaces;
  } // RIPRoutingTable.getForwardInterfaces

  public final Vector getLinks() {
    Vector links = new Vector();
    entryChangeGuard.acquire();
    for ( int i = 0; i < entries.size(); i += 1 ) {
      if ( !links.contains( ( (RIPRoutingEntry) entries.elementAt( i ) ).l ) ) {
	links.addElement( ( (RIPRoutingEntry) entries.elementAt( i ) ).l ) ;
      } // if
    } // for
    entryChangeGuard.release();
    return links;
  } // RIPRoutingTable.getLinks

  public void createTableWindow( NodeRIP n, NetworkRIP net ) {
    if ( tableWindow == null ) {
      tableWindow = new RIPRoutingTableWindow( this, n, net );
    } else {
      tableWindow.repaint();
    } // if
  } // RIPRoutingTable.createTableWindow

 
} // RIPRoutingTable





